<!DOCTYPE html>
<html lang="zh">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>双向绑定的小例子</title>
    <script type="text/javascript">
    (function(window) {
        var web = function(param) {
            //默认参数
            this.attrs = {
                width: 100,
                height: 100,
                top: 300,
                left: 400,
                target: '',
                title: '默认标题'
            };
            for (var t in param) this.attrs[t] = param[t];
            //设置属性的双向绑定及监听
            for (var t in this.attrs) {
                this['_' + t] = this.attrs[t];
                var str = 'Object.defineProperty(this, \''+t+'\', {\
                get: function() {\
                    return this._' + t + ';\
                },\
                set: function(newValue) {\
                    var old = this._' + t + ';\
                    this._' + t + '= newValue;\
                    for (var wat in this._watch) {\
                        if (\'' + t + '\' == wat) {\
                            this._watch[wat](this,newValue,old);\
                        }\
                    }\
                    for (var i=0;i<this._watchlist.length;i++) {\
                        if (\'' + t + '\' == this._watchlist[i].key) {\
                            this._watchlist[i].func(this,newValue,old);\
                        }\
                    }\
                }\
	            });';
                eval(str);
            }

            this._watch = {
                'width': function(sender, val, old) {
                    var target = document.getElementById(sender.target);
                    val = Number(val);
                    if (isNaN(val)) return;
                    target.style.setProperty('width', val + 'px');
                },
                'height': function(sender, val, old) {
                    var target = document.getElementById(sender.target);
                    val = Number(val);
                    if (isNaN(val)) return;
                    target.style.setProperty('height', val + 'px');
                },
                'left': function(sender, val, old) {
                    val = Number(val);
                    if (isNaN(val)) return;
                    var target = document.getElementById(sender.target);
                    target.style.setProperty('left', val + 'px');
                },
                'top': function(sender, val, old) {
                    val = Number(val);
                    if (isNaN(val)) return;
                    var target = document.getElementById(sender.target);
                    target.style.setProperty('top', val + 'px');
                },
                'title': function(sender, val, old) {
                    var target = document.getElementById(sender.target);
                    target.innerHTML = val;
                }

            };
            this._watchlist = new Array(); //自定义监听  
            //添加自定义监听事件
            this.watch = function(watchObj) {
                if (typeof(watchObj) != 'object') return;
                for (var t in watchObj) {
                    this._watchlist.push({
                        key: t,
                        func: watchObj[t]
                    });
                }
            };
            //设置初始值，以触发this._watch()中的监听方法
            for (var t in this.attrs) {
                this[t] = this.attrs[t];
            }
        };
        window.web = web;
    })(window);
    </script>
    <style type="text/css">
    #box {
        background-color: red;
        position: absolute;
        transition: width 0.5s, height 0.5s, left 0.5s, top 0.3s;
    }
    </style>
</head>

<body>
    <h1>利用Object.defineProperty()，写个双向绑定的示例</h1>
    宽度： <input type="text" name="width"><br />
    高度： <input type="text" name="height"><br />
    位置： x<input type="text" name="left" style="width: 60px">y<input type="text" name="top" style="width: 60px"><br />
    标题： <input type="text" name="title"><br />
    <div id="box"></div>
</body>
<script type="text/javascript">
//创建对象，指明控制的元素id
var tm = new web({
    target: 'box'
});
//增加属性监听
tm.watch({
    'title': function(sender, val, old) {
        console.log('标题为：' + val);
    }
});
//设置各个输入框的值和事件
var input = document.querySelectorAll('input');
for (var i = 0; i < input.length; i++) {
    //将tm对象的值设置到输入框
    input[i].value = tm[input[i].getAttribute('name')];
    //设置输入框的事件，当变更时同步更新tm对象
    input[i].addEventListener('input', function(e) {
        var node = event.target ? event.target : event.srcElement;
        var tagname = node.getAttribute('name').toLowerCase();
        tm[tagname] = node.value;
    });
}
</script>

</html>